package bch.maven.plugin.guava.business.jgrapht;

import cn.hutool.core.lang.Pair;
import org.jgrapht.Graph;
import org.jgrapht.alg.cycle.JohnsonSimpleCycles;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.nio.dot.DOTExporter;
import org.jgrapht.nio.Attribute;
import org.jgrapht.nio.DefaultAttribute;

import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

public class GraphCycleVisualExample {

    public static void main(String[] args) throws IOException {
        // 1️⃣ 模拟血缘关系 parentMap：key=子节点，value=(父亲ID, 母亲ID)
        Map<Long, Pair<Long, Long>> parentMap = new HashMap<>();

        // 🔹 第一个环：1 → 2 → 3 → 1
        parentMap.put(1L, Pair.of(2L, null));
        parentMap.put(2L, Pair.of(3L, null));
        parentMap.put(3L, Pair.of(1L, null));

        // 🔹 第二个环：4 → 5 → 6 → 4
        parentMap.put(4L, Pair.of(5L, null));
        parentMap.put(5L, Pair.of(6L, null));
        parentMap.put(6L, Pair.of(4L, null));

        // 🔹 第三个环：7 → 8 → 9 → 10 → 7
        parentMap.put(7L, Pair.of(8L, null));
        parentMap.put(8L, Pair.of(9L, null));
        parentMap.put(9L, Pair.of(10L, null));
        parentMap.put(10L, Pair.of(7L, null));

        // 🔹 非环节点
        parentMap.put(11L, Pair.of(12L, null));
        parentMap.put(12L, Pair.of(13L, null));
        parentMap.put(13L, Pair.of(null, null));

        // 2️⃣ 创建有向图
        Graph<Long, DefaultEdge> graph = new DefaultDirectedGraph<>(DefaultEdge.class);
        for (Map.Entry<Long, Pair<Long, Long>> e : parentMap.entrySet()) {
            Long child = e.getKey();
            Pair<Long, Long> parents = e.getValue();
            graph.addVertex(child);
            if (parents.getKey() != null) {
                graph.addVertex(parents.getKey());
                graph.addEdge(parents.getKey(), child);
            }
            if (parents.getValue() != null) {
                graph.addVertex(parents.getValue());
                graph.addEdge(parents.getValue(), child);
            }
        }

        // 3️⃣ 检测环
        JohnsonSimpleCycles<Long, DefaultEdge> johnson = new JohnsonSimpleCycles<>(graph);
        List<List<Long>> cycles = johnson.findSimpleCycles();

        if (cycles.isEmpty()) {
            System.out.println("图中无环！");
        } else {
            System.out.println("检测到 " + cycles.size() + " 个环：");
            for (int i = 0; i < cycles.size(); i++) {
                System.out.println("环 " + (i + 1) + ": " + String.join(" -> ",
                        cycles.get(i).stream().map(String::valueOf).toArray(String[]::new)));
            }
        }

        // 4️⃣ 输出 Graphviz dot 文件
        exportGraphviz(graph, cycles, "musk_cycle_graph.dot");
    }

    private static String formatCycle(List<Long> cycle) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < cycle.size(); i++) {
            if (i > 0) sb.append(" -> ");
            sb.append(cycle.get(i));
        }
        sb.append(" -> ").append(cycle.get(0));
        return sb.toString();
    }

    /**
     * 将图导出为 Graphviz .dot 文件，可在线或本地可视化
     */
    private static void exportGraphviz(Graph<Long, DefaultEdge> graph,
                                       List<List<Long>> cycles,
                                       String fileName) throws IOException {

        // 找出所有环节点（用于高亮）
        Set<Long> cycleNodes = new HashSet<>();
        for (List<Long> cycle : cycles) {
            cycleNodes.addAll(cycle);
        }

        DOTExporter<Long, DefaultEdge> exporter = new DOTExporter<>(Object::toString);
        exporter.setVertexAttributeProvider(v -> {
            Map<String, Attribute> map = new LinkedHashMap<>();
            if (cycleNodes.contains(v)) {
                map.put("color", DefaultAttribute.createAttribute("red"));
                map.put("style", DefaultAttribute.createAttribute("filled"));
                map.put("fillcolor", DefaultAttribute.createAttribute("lightcoral"));
            } else {
                map.put("color", DefaultAttribute.createAttribute("black"));
            }
            map.put("label", DefaultAttribute.createAttribute(v.toString()));
            return map;
        });

        try (FileWriter writer = new FileWriter(fileName)) {
            exporter.exportGraph(graph, writer);
        }

        System.out.println("✅ Graphviz 文件已导出：" + fileName);
        System.out.println("👉 打开在线可视化工具查看：https://dreampuf.github.io/GraphvizOnline/");
    }
}
